/*
 * File:    ServiceVirtualContext.java
 * Created: 16-Apr-2006
 * Version: $Id: //depot/bitgate/bsse/src/bitgate/util/service/ServiceVirtualContext.java#1 $
 *
 * COPYRIGHT (C) 2006, Bitgate Software, LLC.  All Rights Reserved.
 *
 * software@bitgatesoftware.com
 */

package com.bitgate.util.service;

import static com.bitgate.util.debug.Debug.*;

import java.util.HashMap;

import com.bitgate.util.wildcard.Wildcard;

/**
 * A <code>ServiceVirtualContext</code> object is attached to each running <code>Service</code> to allow for that
 * <code>Service</code> to handle multiple virtual hosts.  Virtual Hosts are attached to each server, and properties for
 * each virtual host are matched by the host in which they match.
 * <p/>
 * Each host can contain a wildcard to make the match more specific to the virtual host.  Each virtual host can contain
 * a set of private properties that can be retrieved at the time they are required, all by the host that was matched.
 * <p/>
 * Properties are generally set the same way they are set in the <code>services.xml</code> file, but they can be set
 * however the programmer wants, through whatever mechanism the programmer desires.  This was simply set this way to
 * make it quicker to match properties for a matched host instead of having to deal with a large number of objects to
 * get the simple task done - plus it's faster this way.
 *
 * @author Kenji Hollis &lt;kenji@bitgatesoftware.com&gt;
 * @version $Id: //depot/bitgate/bsse/src/bitgate/util/service/ServiceVirtualContext.java#1 $
 */
public class ServiceVirtualContext
{
    private final HashMap<String, HashMap<String, String>> virtualHash;

    /**
     * Constructor.
     */
    public ServiceVirtualContext()
    {
    	this.virtualHash = new HashMap<String, HashMap<String, String>>();
    	
    	if (isDebugEnabled()) {
    		debug("Created new service virtual context.");
    	}
    }

    /**
     * Adds a property to a host entry.
     *
     * @param host The host name to add the property to.
     * @param property The property name (similar to the one set in XML) to assign.
     * @param value The value to set for that property.
     */
    public void addProperty(String host, String property, String value)
    {
    	if (this.virtualHash.get(host) == null) {
    		this.virtualHash.put(host, new HashMap<String, String>());
    	}

    	HashMap<String, String> entry = null;

    	entry = this.virtualHash.get(host);
    	entry.put(property, value);
    	this.virtualHash.put(host, entry);

    	if (isDebugEnabled()) {
    		debug("Added property key '" + property + "' value '" + value + "' to host '" + host + "'");
    	}
    }

    /**
     * Retrieves a property by name for a host.
     *
     * @param host The host name to look up.
     * @param property The property to retrieve the value for.
     * @return <code>String</code> containing the value.
     */
    public String getProperty(String host, String property)
    {
    	HashMap<String, String> vsHash = null;

    	vsHash = this.virtualHash.get(host);

    	if (vsHash != null) {
    		return vsHash.get(property);
    	}

    	return null;
    }

    /**
     * Runs through a wildcard match to find the specified host.  Once the host is found, that host is returned.  If no
     * host was found, but an overall wildcard match ("*") was found, the system default wildcard is returned.
     *
     * @param host The hostname that was requested by the client.
     * @return <code>String</code> containing the matching host.
     */
    public String findHost(String host)
    {
		boolean hasStar = false;
		String matchHost = host;
	
		// Web-based requests (HTTP/HTTPS/SOAP/RTSP) have hosts with the format "host:port" in them.  This strips the port.
		if (matchHost.indexOf(":") != -1) {
		    matchHost = matchHost.substring(0, matchHost.indexOf(":"));
		}
	
		for(String key : this.virtualHash.keySet()) {
		    if ("*".equals(key)) {
				hasStar = true;
				continue;
		    }
	
		    String wcKey = Wildcard.toRegexp(key);
	
		    if (matchHost.matches(wcKey)) {
		    	return key;
		    }
		}
	
		if (hasStar) {
		    return "*";
		}
	
		return null;
    }
}
